
#include <BColorArray>
#include <BEvent>
#include <BKeyEvent>
#include <BEvent>
#include <BEvent>
#include <BMouseEvent>
#include <BEvent>
#include <BEvent>
#include <BTextEdit>
#include <BPainter>
#include <BCursor>
#include <BDrag>
#include <BSystem>
#include <BScreen>
#include "member_BWidget.h"
#include "member_BEvent.h"
#include "member_BDrag.h"
#include "IWindow.h"
#include "IGlobal.h"

using namespace BWE;

#ifdef _WIN32

bool IWindow::create()
{
	hwnd = 0;
	hdc = 0;
	context = 0;
	if (boss->frameless())
		style = WS_POPUP | WS_SYSMENU;
	else
		style = WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
	mouseInside = false;

	int  nIconWidth = GetSystemMetrics(SM_CXICON);
	int  nIconHeight = GetSystemMetrics(SM_CYICON);

	const BRect& rect = boss->rect();
	int x = rect.x();
	int y = rect.y();
	int w = rect.width();
	int h = rect.height();

	const wchar_t* ClassName = L"IWindow";

	HINSTANCE hInstance = GetModuleHandle(0);

	WNDCLASSEX wcex;
	memset(&wcex, 0, sizeof(wcex));
	wcex.cbSize = sizeof(wcex);
	wcex.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wcex.lpfnWndProc = WindowProc;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(0, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(0, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszClassName = ClassName;

	ATOM atom = RegisterClassEx(&wcex);

	wchar_t title[256];
	bMbsToWcs(boss->title().cstr(), title);

	hwnd = CreateWindow(ClassName, title, style, x, y, w, h, 0, 0, hInstance, 0);
	if (!hwnd)
	{
		perror("create hwnd failed.");
		return false;
	}

	DragAcceptFiles(hwnd, TRUE);

	//SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
	//BOOL ret0 = SetLayeredWindowAttributes(hwnd, 0, 255, LWA_COLORKEY | LWA_ALPHA);

	hdc = GetDC(hwnd);
	if (!hdc)
	{
		perror("Get hwnd device faild.");
		DestroyWindow(hwnd);
		hwnd = 0;
		return false;
	}

	IWindow* firstWindow = app_windows.first();
	context = CreateContext(hdc);
	if (!context)
	{
		perror("Create GL context faild.");
		DestroyWindow(hwnd);
		hwnd = 0;
		hdc = 0;
		return false;
	}
	if (firstWindow)
	{
		wglShareLists(firstWindow->context, context);
	}

	BOOL ret = UpdateWindow(hwnd);

	return true;
}
bool IWindow::destroy()
{
	if (context)
		wglDeleteContext(context);
	if (hwnd)
		DestroyWindow(hwnd);
	hwnd = 0;
	context = 0;
	return true;
}
bool IWindow::makeCurrent(bool yes)
{
	if (yes)
	{
		if (FALSE == wglMakeCurrent(hdc, context))
		{
			DWORD error = GetLastError();
		}
	}
	else
	{
		if (FALSE == wglMakeCurrent(0, 0))
		{
			DWORD error = GetLastError();
		}
	}
	return true;
}
bool IWindow::swapBuffers()
{
	BOOL ret = SwapBuffers(hdc);
	return ret == TRUE;
}

bool IWindow::setWindowIcon(const BIcon* icon)
{
	if (!icon)
		return false;
	if (const BImage* image = icon->image())
	{
		const BByteArray* pixels = image->pixels();
		const BSize& size = image->size();
		HICON hIcon = (HICON)GetClassLongPtr(hwnd, GCLP_HICON);
		ICONINFO info = { 0 };
		if (GetIconInfo(hIcon, &info))
		{
			BITMAP bitmap = { 0 };
			if (GetObject(info.hbmColor, sizeof(BITMAP), &bitmap))
			{
				if (bitmap.bmBitsPixel == 32)
				{
					LONG size = bitmap.bmWidth * bitmap.bmHeight;bitmap.bmWidthBytes;
					BColorArray colors(size);
					LONG ret0 = ::SetBitmapBits(info.hbmColor, size * sizeof(BColor), pixels->data());
					ULONG_PTR ret1 = ::SetClassLongPtr(hwnd, GCLP_HICON, (LONG_PTR)hIcon);
				}
				//DeleteObject(info.hbmColor);
				//DeleteObject(info.hbmMask);
			}
		}
		return true;
	}
	return false;
}
void IWindow::setFrameless(bool frameless)
{
	if (frameless)
	{
		SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_VISIBLE);
	}
	else
	{
		SetWindowLong(hwnd, GWL_STYLE, WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
	}
}

bool IWindow::setWindowTitle(const BString& title)
{
	if (hwnd)
	{
		wchar_t ustr[256];
		bMbsToWcs(title.cstr(), ustr);
		return TRUE == SetWindowTextW(hwnd, ustr);
	}
	return false;
}
BString IWindow::getWindowTitle()
{
	WCHAR wstr[256];
	int len = GetWindowText(hwnd, wstr, 256);
	char cstr[256];
	bWcsToMbs(wstr, cstr);
	return cstr;
}

bool IWindow::setWindowPos(const BPoint& pos)
{
	if (hwnd)
	{
		WINDOWINFO winfo;
		::GetWindowInfo(hwnd, &winfo);
		if (winfo.rcWindow.left == pos.x() && winfo.rcWindow.top == pos.y())
			return false;
		int x = pos.x() - (winfo.rcClient.left - winfo.rcWindow.left);
		int y = pos.y() - (winfo.rcClient.top - winfo.rcWindow.top);
		int width = winfo.rcWindow.right - winfo.rcWindow.left;
		int height = winfo.rcWindow.bottom - winfo.rcWindow.top;
		BOOL ret = MoveWindow(hwnd, x, y, width, height, TRUE);
		return true;
	}
	return false;
}
BPoint IWindow::getWindowPos()
{
	if (hwnd)
	{
		RECT windowRect;
		GetWindowRect(hwnd, &windowRect);
		return BPoint(windowRect.left, windowRect.top);
	}
	return boss->pos();
}

bool IWindow::setWindowSize(const BSize& size)
{
	if (hwnd)
	{
		resized = true;
		WINDOWINFO winfo;
		::GetWindowInfo(hwnd, &winfo);
		int x = winfo.rcWindow.left;
		int y = winfo.rcWindow.top;
		int width = size.width() + (winfo.rcWindow.right - winfo.rcWindow.left) - (winfo.rcClient.right - winfo.rcClient.left);
		int height = size.height() + (winfo.rcWindow.bottom - winfo.rcWindow.top) - (winfo.rcClient.bottom - winfo.rcClient.top);
		return MoveWindow(hwnd, x, y, width, height, TRUE);
	}
	return false;
}
BSize IWindow::getWindowSize()
{
	if (hwnd)
	{
		RECT centerRect;
		GetClientRect(hwnd, &centerRect);
		int w = centerRect.right - centerRect.left;
		int h = centerRect.bottom - centerRect.top;
		return BSize(w, h);
	}
	return boss->size();
}

void IWindow::setInputPoint(const BPoint& point)
{
	HIMC himc = ImmGetContext(hwnd);
	COMPOSITIONFORM compForm;
	compForm.dwStyle = CFS_POINT;
	compForm.ptCurrentPos.x = point.x();
	compForm.ptCurrentPos.y = point.y();
	BOOL ret = ImmSetCompositionWindow(himc, &compForm);
	ImmReleaseContext(hwnd, himc);

}
BPoint IWindow::getInputPoint() const
{
	HIMC himc = ImmGetContext(hwnd);
	COMPOSITIONFORM compForm;
	memset(&compForm, 0, sizeof(COMPOSITIONFORM));
	BOOL ret = ImmGetCompositionWindow(himc, &compForm);
	ImmReleaseContext(hwnd, himc);
	BPoint point(compForm.ptCurrentPos.x, compForm.ptCurrentPos.y);
	return point;
}

bool IWindow::isMaximized()
{
	return TRUE == IsZoomed(hwnd);
}
bool IWindow::isMinimized()
{
	return TRUE == IsIconic(hwnd);
}

void IWindow::showNormal()
{
	if (hwnd)
	{
		ShowWindow(hwnd, SW_SHOWNORMAL);
		shown = true;
	}
}
void IWindow::showMaximized()
{
	if (hwnd)
	{
		ShowWindow(hwnd, SW_SHOWMAXIMIZED);
		shown = true;
	}
}
void IWindow::showMinimized()
{
	if (hwnd)
	{
		ShowWindow(hwnd, SW_SHOWMINIMIZED);
		shown = false;
	}
}
void IWindow::showFullScreen()
{
	if (hwnd)
	{
		ShowWindow(hwnd, SW_SHOWMAXIMIZED);
		shown = true;
	}
}
void IWindow::hideWindow()
{
	if (hwnd)
	{
		ShowWindow(hwnd, SW_HIDE);
		shown = false;
	}
}

void IWindow::freshCursor()
{
	BImage* image = 0;
	CursorType type = Cursor_None;
	if (hoverCursor)
	{
		type = hoverCursor->type();
		image = hoverCursor->image(type);
	}
	if (image)
	{
		while (ShowCursor(FALSE) >= 0)
			ShowCursor(FALSE);
		return;
	}
	while (ShowCursor(TRUE) < 0)
		ShowCursor(TRUE);
	switch (type)
	{
	case Cursor_None:
	case Cursor_Arrow:
		SetCursor(LoadCursor(0, IDC_ARROW));
		break;
	case Cursor_Ibeam:
		SetCursor(LoadCursor(0, IDC_IBEAM));
		break;
	case Cursor_Cross:
		SetCursor(LoadCursor(0, IDC_CROSS));
		break;
	case Cursor_Wait:
		SetCursor(LoadCursor(0, IDC_WAIT));
		break;
	case Cursor_Forbidden:
		SetCursor(LoadCursor(0, IDC_NO));
		break;
	case Cursor_Hand:
		SetCursor(LoadCursor(0, IDC_HAND));
		break;
	case Cursor_Help:
		SetCursor(LoadCursor(0, IDC_HELP));
		break;
	case Cursor_SizeVer:
	case Cursor_SizeTop:
	case Cursor_SizeBottom:
		SetCursor(LoadCursor(0, IDC_SIZENS));
		break;
	case Cursor_SizeHor:
	case Cursor_SizeLeft:
	case Cursor_SizeRight:
		SetCursor(LoadCursor(0, IDC_SIZEWE));
		break;
	case Cursor_SizeLeftTop:
	case Cursor_SizeRightBottom:
		SetCursor(LoadCursor(0, IDC_SIZENWSE));
		break;
	case Cursor_SizeLeftBottom:
	case Cursor_SizeRightTop:
		SetCursor(LoadCursor(0, IDC_SIZENESW));
		break;
	case Cursor_SizeAll:
		SetCursor(LoadCursor(0, IDC_SIZEALL));
		break;
	case Cursor_UpArrow:
		SetCursor(LoadCursor(0, IDC_UPARROW));
		break;
	default:
		break;
	}
}

Button filterButton(UINT message)
{
	switch(message)
	{
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_LBUTTONDBLCLK:
		return Button_Left;
		
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_MBUTTONDBLCLK:
		return Button_Middle;
		
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_RBUTTONDBLCLK:
		return Button_Right;
		
	}
	return Button_None;
}

HGLRC BWE::CreateContext(HDC hdc)
{
	PIXELFORMATDESCRIPTOR pixelFormat;
	memset(&pixelFormat, 0, sizeof(pixelFormat));
	pixelFormat.nSize = sizeof(pixelFormat);
	pixelFormat.nVersion = 1;
	pixelFormat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	pixelFormat.iPixelType = PFD_TYPE_RGBA;
	pixelFormat.cColorBits = 32;
	pixelFormat.cDepthBits = 32;
	pixelFormat.iLayerType = PFD_MAIN_PLANE;

	int pixelFormatIndex = ChoosePixelFormat(hdc, &pixelFormat);
	if (pixelFormatIndex == 0)
		return 0;

	DescribePixelFormat(hdc, pixelFormatIndex, sizeof(PIXELFORMATDESCRIPTOR), &pixelFormat);

	int result = SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat);
	if (!result)
		return 0;

	return wglCreateContext(hdc);
}

LRESULT CALLBACK BWE::WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	IWindow* window = 0;
	for (int i = 0; i < app_windows.size(); i++)
	{
		IWindow* w = app_windows[i];
		if (!w->boss)
			continue;
		if (w->hwnd == hwnd)
		{
			window = w;
			break;
		}
	}

	if (window)
	{
		if (!window->procMessage(message, wparam, lparam))
		{
			return 0;
		}
	}
	if (message == WM_CLOSE)
		return 0;
	return DefWindowProc(hwnd, message, wparam, lparam);
}
bool IWindow::procMessage(UINT message, WPARAM wparam, LPARAM lparam)
{
	switch(message)
	{
	case WM_CREATE:
	{
		refresh = true;
		break;
	}
	case WM_ACTIVATE:
	{
		WORD type = LOWORD(wparam);
		WORD mini = HIWORD(wparam);
		if (type == WA_INACTIVE)
		{
			this->focus(0);
			if (hoverWidget)
			{
				mouse_event.reset(Event_MouseLeave);
				widget_member(hoverWidget)->procEvent(mouse_event);
				mouse_event.reset(Event_Hover, false);
				while (hoverWidget)
				{
					widget_member(hoverWidget)->state.hovered = false;
					widget_member(hoverWidget)->procEvent(mouse_event);
					hoverWidget = widget_member(hoverWidget)->parent;
				}
				hoverWidget = 0;
				tipsBoard.reset(0);
				refresh = true;
			}
		}
		BEvent event(Event_Active, type != WA_INACTIVE);
		widget_member(boss)->procEvent(event);
		break;
	}
	case WM_CLOSE:
	{
		BEvent event(Event_Close);
		widget_member(boss)->procEvent(event);
		break;
	}
	case WM_PAINT:
	{
		refresh = true;
		break;
	}
	case WM_SETCURSOR:
	{
		break;
	}
	case WM_TIMER:
	{
		if (wparam)
		{
			KillTimer(hwnd, wparam);
		}
		break;
	}
	case WM_MOVE:
	{
		short x = LOWORD(lparam);
		short y = HIWORD(lparam);
		widget_member(boss)->syncWindowPos(BPoint(x, y));
		break;
	}
	case WM_SIZE:
	{
		resized = true;
		int width = LOWORD(lparam);
		int height = HIWORD(lparam);
		widget_member(boss)->syncWindowSize(BSize(width, height));
		break;
	}
	case WM_SETFOCUS:
	{
		mouse_pressed = false;
		focusing = true;
		BEvent focusEvent(Event_Focus);
		focusEvent.setValue(true);
		widget_member(boss)->procEvent(focusEvent);
		break;
	}
	case WM_KILLFOCUS:
	{
		ReleaseCapture();
		mouse_pressed = false;
		focusing = false;
		BEvent focusEvent(Event_Focus);
		focusEvent.setValue(false);
		widget_member(boss)->procEvent(focusEvent);
		keyStates.fill(false);
		break;
	}
	case WM_KEYDOWN:
	{
		if (Key key = filterKey(wparam))
		{
			keyStates[key] = true;
			BKeyEvent keyEvent(Event_KeyPress, key);
			this->procKeyPress(keyEvent);
		}
		break;
	}
	case WM_KEYUP:
	{
		if (Key key = filterKey(wparam))
		{
			keyStates[key] = false;
			BKeyEvent keyEvent(Event_KeyRelease, key);
			this->procKeyRelease(keyEvent);
		}
		break;
	}
	case WM_CHAR:
	{
		if (focusWidget)
		{
			short schr = (short)LOWORD(wparam);
			short flag = (short)LOWORD(lparam);
			if (31 < schr && schr < 127)
			{
				BCode code((char)schr);
				const char* ustr = code.str();
				BEvent event(Event_Input, code);
				event_member(&event)->window = this;
				widget_member(focusWidget)->procEvent(event);
			}
		}
		break;
	}
	case WM_SYSKEYDOWN:
	{
		if (Key key = filterKey(wparam))
		{
			keyStates[key] = true;
			BKeyEvent keyEvent(Event_KeyPress, key);
			this->procKeyPress(keyEvent);
		}
		return false;
	}
	case WM_SYSKEYUP:
	{
		if (Key key = filterKey(wparam))
		{
			keyStates[key] = false;
			BKeyEvent keyEvent(Event_KeyRelease, key);
			this->procKeyRelease(keyEvent);
		}
		return false;
	}
	case WM_SYSCHAR:
	{
		break;
	}
	case WM_IME_SETCONTEXT:
	{
		//puts("WM_IME_SetContext");
		break;
	}
	case WM_IME_NOTIFY:
	{
		//puts("WM_IME_Notify");
		break;
	}
	case WM_IME_CONTROL:
	{
		//puts("WM_IME_Control");
		break;
	}
	case WM_IME_COMPOSITIONFULL:
	{
		//puts("WM_IME_CompositionFull");
		break;
	}
	case WM_IME_SELECT:
	{
		//puts("WM_IME_Select");
		break;
	}
	case WM_IME_CHAR:
	{
		if (focusWidget)
		{
			wchar_t schr = (wchar_t)LOWORD(wparam);
			short flag = (short)LOWORD(lparam);
			if (schr > 255)
			{
				wchar_t wstr[2] = { schr, 0 };
				char cstr[5] = { 0 };
				bWcsToMbs(wstr, cstr);
				BEvent event(Event_Input, BCode(cstr));
				event_member(&event)->window = this;
				widget_member(focusWidget)->procEvent(event);
				if (event.result().is<BPoint>())
				{
					const BPoint& pos = event.result();
					BPoint abPos = focusWidget->absolutePos() + pos;
					setInputPoint(abPos);
				}
			}
		}
		break;
	}
	case WM_IME_REQUEST:
	{
		//puts("WM_IME_Request");
		switch (wparam)
		{
		case IMR_CANDIDATEWINDOW:
			break;
		case IMR_COMPOSITIONFONT:
			break;
		case IMR_CONFIRMRECONVERTSTRING:
			break;
		case IMR_DOCUMENTFEED:
			break;
		case IMR_QUERYCHARPOSITION:
			break;
		case IMR_RECONVERTSTRING:
			break;
		}
		break;
	}
	case WM_LBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_RBUTTONDOWN:
	{
		if (widget_member(boss)->frameless)
			SetCapture(hwnd);
		Button button = filterButton(message);
		BPoint absolutePos((short)LOWORD(lparam), (short)HIWORD(lparam));
		BPoint globalPos = BCursor::GetPos();
		BMouseEvent mouseEvent(Event_MousePress, button);
		event_member(&mouseEvent)->window = this;
		mouseEvent.setAbsolutePos(absolutePos);
		mouseEvent.setGlobalPos(globalPos);
		this->procMousePress(mouseEvent);
		break;
	}
	case WM_LBUTTONUP:
	case WM_MBUTTONUP:
	case WM_RBUTTONUP:
	{
		if (widget_member(boss)->frameless)
			ReleaseCapture();
		Button button = filterButton(message);
		BPoint absolutePos((short)LOWORD(lparam), (short)HIWORD(lparam));
		BPoint globalPos = BCursor::GetPos();
		BMouseEvent mouseEvent(Event_MouseRelease, button);
		event_member(&mouseEvent)->window = this;
		mouseEvent.setAbsolutePos(absolutePos);
		mouseEvent.setGlobalPos(globalPos);
		this->procMouseRelease(mouseEvent);
		break;
	}
	case WM_CAPTURECHANGED:
	{
		break;
	}
	case WM_MOUSEMOVE:
	{
		if (!mouseInside)
		{
			mouseInside = true;
			mouse_pressed = false;
			hoverWidget = boss;
			BMouseEvent mouseEvent(Event_MouseEnter, mouse_button);
			event_member(&mouseEvent)->window = this;
			widget_member(boss)->procEvent(mouseEvent);

			TRACKMOUSEEVENT eventTrack;
			eventTrack.cbSize = sizeof(TRACKMOUSEEVENT);
			eventTrack.dwFlags = TME_LEAVE | TME_HOVER;
			eventTrack.hwndTrack = hwnd;
			eventTrack.dwHoverTime = 0;
			TrackMouseEvent(&eventTrack);
		}
		BPoint absolutePos((short)LOWORD(lparam), (short)HIWORD(lparam));
		BPoint globalPos = BCursor::GetPos();
		BMouseEvent mouseEvent(Event_MouseMove, mouse_button);
		event_member(&mouseEvent)->window = this;
		mouseEvent.setAbsolutePos(absolutePos);
		mouseEvent.setGlobalPos(globalPos);
		this->procMouseMove(mouseEvent);
		break;
	}
	case WM_MOUSEHOVER:
	{
		BPoint absolutePos((short)LOWORD(lparam), (short)HIWORD(lparam));
		//printf("mouse hover event : %d\t%d\n", absolutePos.x(), absolutePos.y());
		break;
	}
	case WM_MOUSELEAVE:
	{
		mouseInside = false;
		if (hoverWidget)
		{
			BMouseEvent mouseEvent(Event_MouseLeave, mouse_button);
			event_member(&mouseEvent)->window = this;
			widget_member(hoverWidget)->procEvent(mouseEvent);
			hoverWidget = 0;
		}
		break;
	}
	case WM_MOUSEWHEEL:
	{
		BPoint globalPos((short)LOWORD(lparam), (short)HIWORD(lparam));
		BPoint absolutePos = globalPos - boss->pos();
		int wheel = (short)HIWORD(wparam) / 120;
		
		BMouseEvent mouseEvent(Event_MouseWheel, Button_Middle);
		event_member(&mouseEvent)->window = this;
		mouseEvent.setGlobalPos(globalPos);
		mouseEvent.setAbsolutePos(absolutePos);
		mouseEvent.setWheel(wheel);
		this->procMouseWheel(mouseEvent);
		break;
	}
	case WM_CLIPBOARDUPDATE:
	{
		break;
	}
	case WM_DROPFILES:
	{
		wchar_t fileName[256];
		char path[256];
		WIN32_FIND_DATA findata;
		HDROP hdrop = (HDROP)wparam;
		POINT point;
		DragQueryPoint(hdrop, &point);
		int count = DragQueryFile(hdrop, -1, 0, 0);
		if (count > 0 && hoverWidget)
		{
			BPoint pos = hoverWidget->mapFrom(boss, BPoint(point.x, point.y));
			BDrag* drag = new BDrag();
			drag->setPos(pos);

			BStringArray& fileNames = drag_member(drag)->value.fill<BStringArray>();
			for (int i = 0; i < count; i++)
			{
				DragQueryFileW(hdrop, i, fileName, 256);
				HANDLE handle = FindFirstFile(fileName, &findata);
				if (handle == INVALID_HANDLE_VALUE)
					continue;
				if (findata.dwFileAttributes == INVALID_FILE_ATTRIBUTES)
					continue;
				bWcsToMbs(fileName, path);
				fileNames.append(path);
				fileNames.last().replace('\\', '/');
			}

			BMouseEvent mouseEvent;
			event_member(&mouseEvent)->window = this;
			mouseEvent.setType(Event_DragDrop);
			mouseEvent.setValue(drag);
			mouseEvent.setPos(pos);
			widget_member(hoverWidget)->procEvent(mouseEvent);
		}
		DragFinish(hdrop);
		break;
	}
	case WM_NCMOUSEMOVE:
	{
		break;
	}
	case WM_WINDOWPOSCHANGING:
	{
		break;
	}
	case WM_WINDOWPOSCHANGED:
	{
		break;
	}
	case WM_ACTIVATEAPP:
	{
		break;
	}
	case WM_INPUTLANGCHANGE:
	{
		break;
	}
	case WM_IME_ENDCOMPOSITION:
	{
		break;
	}
	case WM_NCACTIVATE:
	{
		break;
	}
	case WM_NCHITTEST:
	{
		break;
	}
	case WM_CONTEXTMENU:
	{
		break;
	}
	case WM_SYSDEADCHAR:
	{
		break;
	}
	case WM_UNICHAR:
	{
		break;
	}
	default:
		return true;
	}
	return true;
}
Key IWindow::filterKey(WPARAM wparam)
{
	switch (wparam)
	{
	case 0x01:	return Key_LButton;
	case 0x02:	return Key_RButton;
	case 0x04:	return Key_MButton;

	case 0x25:	return Key_Left;
	case 0x26:	return Key_Up;
	case 0x27:	return Key_Right;
	case 0x28:	return Key_Down;

	case 0x30:	return Key_0;
	case 0x31:	return Key_1;
	case 0x32:	return Key_2;
	case 0x33:	return Key_3;
	case 0x34:	return Key_4;
	case 0x35:	return Key_5;
	case 0x36:	return Key_6;
	case 0x37:	return Key_7;
	case 0x38:	return Key_8;
	case 0x39:	return Key_9;

	case 0x41:	return Key_A;
	case 0x42:	return Key_B;
	case 0x43:	return Key_C;
	case 0x44:	return Key_D;
	case 0x45:	return Key_E;
	case 0x46:	return Key_F;
	case 0x47:	return Key_G;
	case 0x48:	return Key_H;
	case 0x49:	return Key_I;
	case 0x4A:	return Key_J;
	case 0x4B:	return Key_K;
	case 0x4C:	return Key_L;
	case 0x4D:	return Key_M;
	case 0x4E:	return Key_N;
	case 0x4F:	return Key_O;
	case 0x50:	return Key_P;
	case 0x51:	return Key_Q;
	case 0x52:	return Key_R;
	case 0x53:	return Key_S;
	case 0x54:	return Key_T;
	case 0x55:	return Key_U;
	case 0x56:	return Key_V;
	case 0x57:	return Key_W;
	case 0x58:	return Key_X;
	case 0x59:	return Key_Y;
	case 0x5A:	return Key_Z;

	case VK_NUMPAD0:	return Key_Num0;
	case VK_NUMPAD1:	return Key_Num1;
	case VK_NUMPAD2:	return Key_Num2;
	case VK_NUMPAD3:	return Key_Num3;
	case VK_NUMPAD4:	return Key_Num4;
	case VK_NUMPAD5:	return Key_Num5;
	case VK_NUMPAD6:	return Key_Num6;
	case VK_NUMPAD7:	return Key_Num7;
	case VK_NUMPAD8:	return Key_Num8;
	case VK_NUMPAD9:	return Key_Num9;

	case VK_ESCAPE:		return Key_Escape;
	case VK_NUMLOCK:	return Key_NumLock;
	case VK_MULTIPLY:	return Key_Multiply;
	case VK_ADD:		return Key_Add;
	case VK_SEPARATOR:	return Key_Separator;
	case VK_SUBTRACT:	return Key_Sub;
	case VK_DIVIDE:		return Key_Divide;
	case VK_PAUSE:		return Key_Pause;

	case VK_F1:			return Key_F1;
	case VK_F2:			return Key_F2;
	case VK_F3:			return Key_F3;
	case VK_F4:			return Key_F4;
	case VK_F5:			return Key_F5;
	case VK_F6:			return Key_F6;
	case VK_F7:			return Key_F7;
	case VK_F8:			return Key_F8;
	case VK_F9:			return Key_F9;
	case VK_F10:		return Key_F10;
	case VK_F11:		return Key_F11;
	case VK_F12:		return Key_F12;

	case VK_HOME:		return Key_Home;
	case VK_END:		return Key_End;
	case VK_PRIOR:		return Key_PageUp;
	case VK_NEXT:		return Key_PageDown;

	case VK_TAB:		return Key_Tab;
	case VK_SPACE:		return Key_Space;

	case VK_DELETE:		return Key_Delete;
	case VK_BACK:		return Key_Back;
	case VK_RETURN:		return Key_Enter;

	case VK_OEM_PLUS:		return Key_Plus;
	case VK_OEM_COMMA:		return Key_Comma;
	case VK_OEM_MINUS:		return Key_Minus;
	case VK_OEM_PERIOD:		return Key_Period;
	
	case VK_OEM_1:			return Key_Semicolon;
	case VK_OEM_2:			return Key_Backslash;
	case VK_OEM_4:			return Key_LSquareBracket;
	case VK_OEM_5:			return Key_Slash;
	case VK_OEM_6:			return Key_RSquareBracket;
	case VK_OEM_7:			return Key_Quotation;

	case VK_SHIFT:
		keyStates[Key_LShift] = GetKeyState(VK_LSHIFT) < 0;
		keyStates[Key_RShift] = GetKeyState(VK_RSHIFT) < 0;
		return Key_Shift;

	case VK_CONTROL:
		keyStates[Key_LCtrl] = GetKeyState(VK_LCONTROL) < 0;
		keyStates[Key_RCtrl] = GetKeyState(VK_RCONTROL) < 0;
		return Key_Ctrl;

	case VK_MENU:
		keyStates[Key_LAlt] = GetKeyState(VK_LMENU) < 0;
		keyStates[Key_RAlt] = GetKeyState(VK_RMENU) < 0;
		return Key_Alt;

	case VK_LWIN:
	case VK_RWIN:
		keyStates[Key_LSys] = GetKeyState(VK_LWIN) < 0;
		keyStates[Key_RSys] = GetKeyState(VK_RWIN) < 0;
		return Key_Sys;

	default:
		return Key_None;
	}
}

#endif
